package com.joe.codemother.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.io.FileUtil;
import com.joe.codemother.constant.FileConstant;
import com.joe.codemother.core.AiGenerateCodeFacede;
import com.joe.codemother.entity.User;
import com.joe.codemother.entity.dto.AppAdminQueryRequest;
import com.joe.codemother.entity.dto.AppFeaturedQueryRequest;
import com.joe.codemother.entity.dto.AppMyQueryRequest;
import com.joe.codemother.entity.enums.GenerateTypeEnum;
import com.joe.codemother.exception.BusinessException;
import com.joe.codemother.exception.ErrorCode;
import com.joe.codemother.util.ThrowUtils;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.spring.service.impl.ServiceImpl;
import com.joe.codemother.entity.App;
import com.joe.codemother.mapper.AppMapper;
import com.joe.codemother.service.AppService;
import jakarta.annotation.Resource;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.RandomStringUtils;
import org.springframework.aot.hint.annotation.Reflective;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Flux;

import java.io.File;
import java.time.LocalDateTime;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicReference;

import com.joe.codemother.service.ChatHistoryService;
import org.springframework.transaction.annotation.Transactional;
import cn.hutool.core.util.StrUtil;

/**
 * 应用 服务层实现。
 *
 * @author joe
 */
@Service
@Slf4j
public class AppServiceImpl extends ServiceImpl<AppMapper, App>  implements AppService{

	@Resource
	AiGenerateCodeFacede aiGenerateCodeFacede;

	@Resource
	private ChatHistoryService chatHistoryService;

	@Override
	public QueryWrapper getMyQueryWrapper(AppMyQueryRequest request, Long userId) {
		ThrowUtils.throwIf(request == null || userId == null, ErrorCode.PARAMS_ERROR);
		String appName = request.getAppName();
		return QueryWrapper.create()
				.eq("userId", userId)
				.like("appName", appName)
				.orderBy("updateTime", false);
	}

	@Override
	public QueryWrapper getFeaturedQueryWrapper(AppFeaturedQueryRequest request) {
		ThrowUtils.throwIf(request == null, ErrorCode.PARAMS_ERROR);
		String appName = request.getAppName();
		// 约定：priority > 0 为精选
		return QueryWrapper.create()
				.gt("priority", 0)
				.like("appName", appName)
				.orderBy("priority", false)
				.orderBy("updateTime", false);
	}

	@Override
	public QueryWrapper getAdminQueryWrapper(AppAdminQueryRequest request) {
		ThrowUtils.throwIf(request == null, ErrorCode.PARAMS_ERROR);
		Long id = request.getId();
		String appName = request.getAppName();
		String cover = request.getCover();
		String codeGenType = request.getCodeGenType();
		String deployKey = request.getDeployKey();
		Integer priority = request.getPriority();
		Long userId = request.getUserId();
		String sortField = request.getSortField();
		String sortOrder = request.getSortOrder();
		return QueryWrapper.create()
				.eq("id", id)
				.eq("cover", cover)
				.eq("codeGenType", codeGenType)
				.eq("deployKey", deployKey)
				.eq("priority", priority)
				.eq("userId", userId)
				.like("appName", appName)
				.orderBy(sortField, "ascend".equals(sortOrder));
	}

	@Override
	public Flux<String> chatToGenCode(String userMessage, Long appId, User loginUser) {
		ThrowUtils.throwIf(loginUser == null || appId == null, ErrorCode.PARAMS_ERROR);
		Long userId = loginUser.getId();
		App app = this.getOne(QueryWrapper.create().eq("Id", appId));
		ThrowUtils.throwIf(app == null, ErrorCode.PARAMS_ERROR,"no app found!");
		log.info("user is {}, userId is {}", userId, app.getUserId());
		ThrowUtils.throwIf(!Objects.equals(userId, app.getUserId()), ErrorCode.NO_AUTH_ERROR);
		// 先保存用户消息
		chatHistoryService.saveUserMessage(appId, userId, userMessage);
		GenerateTypeEnum typeEnum = GenerateTypeEnum.getTypeByValue(app.getCodeGenType());
		AtomicReference<StringBuilder> bufferRef = new AtomicReference<>(new StringBuilder());
		return aiGenerateCodeFacede.generateAiCodeStream(userMessage,typeEnum,appId)
				.doOnNext(chunk -> bufferRef.get().append(chunk))
				.doOnComplete(() -> {
					String full = bufferRef.get().toString();
					if (StrUtil.isNotBlank(full)) {
						chatHistoryService.saveAiMessage(appId, userId, full);
					}
				})
				.doOnError(e -> chatHistoryService.saveError(appId, userId, StrUtil.sub(e.getMessage(), 0, 2000)));
	}

	@Override
	public String deployCode(Long appId, User loginUser) {
		ThrowUtils.throwIf(loginUser == null || appId == null, ErrorCode.PARAMS_ERROR,"no app or user found!");
		App app = this.getOne(QueryWrapper.create().eq("Id", appId));
		String deployKey = app.getDeployKey();
		if(Objects.isNull(deployKey)){
			deployKey = RandomStringUtils.randomAlphanumeric(6);
		}
		app.setDeployKey(deployKey);
		String genType = app.getCodeGenType();
		String fileDir = FileConstant.FILE_ROOT_PATH + File.separator + genType + "_" + appId;
		File file = new File(fileDir);
		ThrowUtils.throwIf(!file.isDirectory() || !file.exists(), ErrorCode.NO_AUTH_ERROR,"please generate file first!");
		String deployDir = FileConstant.DEPLOY_ROOT_PATH + File.separator + deployKey;
		FileUtil.copyContent(file,new File(deployDir),true);
		App updateApp = new App();
		updateApp.setId(appId);
		updateApp.setDeployKey(deployKey);
		updateApp.setDeployedTime(LocalDateTime.now());
		boolean save = this.saveOrUpdate(updateApp);
		if(save) {
			return String.format("http://localhost:8123/api/static/%s",deployKey);
		}
		return "";
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public boolean removeById(Long id) {
		// 先删除该应用的对话历史
		chatHistoryService.remove(QueryWrapper.create().eq("appId", id));
		// 再删除应用
		return super.removeById(id);
	}
}
